// SampleDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Sample.h"
#include "SampleDlg.h"
#include "ZKFPCap.h"
#include "ZKFinger.h"
#include "futil.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define REGISTER_FINGER_COUNT 3

static HMODULE ZKFPCapLib = NULL;
static HMODULE ZKFingerLib = NULL;
static HANDLE ZKFPCapHandle = NULL;
static HANDLE ZKFingerHandle = NULL;
static HANDLE gThread = NULL;
HWND hwnd;

static int gInited = 0;
static int gConnected = 0;
static int g_bIsTimeToDie = 0;
static int g_nWidth = 0;
static int g_nHeight = 0;
static int g_FPBufferSize = 0;
static BYTE *g_FPBuffer = NULL;
static bool gIsEnroll = false;
static int gPressTimes = 0;
static int gEnrollCount = 0;
static BYTE gTmp1[2048] = {0}, gTmp2[2048] = {0}, gTmp3[2048] = {0};

int loadZKFPCapLib();
int loadZKFingerLib();

// CSampleDlg dialog




CSampleDlg::CSampleDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSampleDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSampleDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CSampleDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_MESSAGE(MESSAGE_FP_RECEIVED, OnFPReceived)

	ON_BN_CLICKED(IDC_BTN_INIT, &CSampleDlg::OnBnClickedBtnInit)
	ON_BN_CLICKED(IDC_BTN_OPEN, &CSampleDlg::OnBnClickedBtnOpen)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_BTN_ENROLL, &CSampleDlg::OnBnClickedBtnEnroll)
	ON_BN_CLICKED(IDC_BTN_IDENTIFY, &CSampleDlg::OnBnClickedBtnIdentify)
	ON_BN_CLICKED(IDC_BTN_GREEN, &CSampleDlg::OnBnClickedBtnGreen)
	ON_BN_CLICKED(IDC_BTN_RED, &CSampleDlg::OnBnClickedBtnRed)
	ON_BN_CLICKED(IDC_BTN_BEEP, &CSampleDlg::OnBnClickedBtnBeep)
END_MESSAGE_MAP()


// CSampleDlg message handlers

BOOL CSampleDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	hwnd = GetSafeHwnd();

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CSampleDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CSampleDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

int loadZKFPCapLib()
{
	ZKFPCapLib = LoadLibrary("ZKFPCap.dll");

	if(ZKFPCapLib)
	{
		sensorInit = (T_sensorInit)GetProcAddress(ZKFPCapLib, "sensorInit");
		sensorFree = (T_sensorFree)GetProcAddress(ZKFPCapLib, "sensorFree");
		sensorOpen = (T_sensorOpen)GetProcAddress(ZKFPCapLib, "sensorOpen");
		sensorClose = (T_sensorClose)GetProcAddress(ZKFPCapLib, "sensorClose");
		sensorGetCount = (T_sensorGetCount)GetProcAddress(ZKFPCapLib, "sensorGetCount");
		sensorGetVersion = (T_sensorGetVersion)GetProcAddress(ZKFPCapLib, "sensorGetVersion");
		sensorCapture = (T_sensorCapture)GetProcAddress(ZKFPCapLib, "sensorCapture");
		sensorGetParameter = (T_sensorGetParameter)GetProcAddress(ZKFPCapLib, "sensorGetParameter");
		sensorSetParameter = (T_sensorSetParameter)GetProcAddress(ZKFPCapLib, "sensorSetParameter");
		sensorGetParameterEx = (T_sensorGetParameterEx)GetProcAddress(ZKFPCapLib, "sensorGetParameterEx");
		sensorSetParameterEx = (T_sensorSetParameterEx)GetProcAddress(ZKFPCapLib, "sensorSetParameterEx");

		if(NULL == sensorInit)
		{
			return 0;
		}
		return 1;
	}

	return 0;
}

int loadZKFingerLib()
{
	ZKFingerLib = LoadLibrary("ZKFinger10.dll");

	if(ZKFingerLib)
	{
		BIOKEY_INIT = (T_BIOKEY_INIT)GetProcAddress(ZKFingerLib, "BIOKEY_INIT");
		BIOKEY_CLOSE = (T_BIOKEY_CLOSE)GetProcAddress(ZKFingerLib, "BIOKEY_CLOSE");
		BIOKEY_SET_PARAMETER = (T_BIOKEY_SET_PARAMETER)GetProcAddress(ZKFingerLib, "BIOKEY_SET_PARAMETER");
		BIOKEY_MATCHINGPARAM = (T_BIOKEY_MATCHINGPARAM)GetProcAddress(ZKFingerLib, "BIOKEY_MATCHINGPARAM");
		BIOKEY_GETLASTQUALITY = (T_BIOKEY_GETLASTQUALITY)GetProcAddress(ZKFingerLib, "BIOKEY_GETLASTQUALITY");
		BIOKEY_GETLASTERROR = (T_BIOKEY_GETLASTERROR)GetProcAddress(ZKFingerLib, "BIOKEY_GETLASTERROR");
		BIOKEY_EXTRACT = (T_BIOKEY_EXTRACT)GetProcAddress(ZKFingerLib, "BIOKEY_EXTRACT");
		BIOKEY_GENTEMPLATE = (T_BIOKEY_GENTEMPLATE)GetProcAddress(ZKFingerLib, "BIOKEY_GENTEMPLATE");
		BIOKEY_GENTEMPLATE_SP = (T_BIOKEY_GENTEMPLATE_SP)GetProcAddress(ZKFingerLib, "BIOKEY_GENTEMPLATE_SP");
		BIOKEY_DB_ADD = (T_BIOKEY_DB_ADD)GetProcAddress(ZKFingerLib, "BIOKEY_DB_ADD");
		BIOKEY_DB_DEL = (T_BIOKEY_DB_DEL)GetProcAddress(ZKFingerLib, "BIOKEY_DB_DEL");
		BIOKEY_DB_COUNT = (T_BIOKEY_DB_COUNT)GetProcAddress(ZKFingerLib, "BIOKEY_DB_COUNT");
		BIOKEY_DB_CLEAR = (T_BIOKEY_DB_CLEAR)GetProcAddress(ZKFingerLib, "BIOKEY_DB_CLEAR");
		BIOKEY_IDENTIFYTEMP = (T_BIOKEY_IDENTIFYTEMP)GetProcAddress(ZKFingerLib, "BIOKEY_IDENTIFYTEMP");
		BIOKEY_VERIFY = (T_BIOKEY_VERIFY)GetProcAddress(ZKFingerLib, "BIOKEY_VERIFY");

		if(NULL == BIOKEY_INIT)
		{
			return 0;
		}
		return 1;
	}

	return 0;
}

DWORD WINAPI GetImage(LPVOID pParam)      
{
	while(!g_bIsTimeToDie)
	{
		memset(g_FPBuffer, 0, g_FPBufferSize);
		if(sensorCapture(ZKFPCapHandle, g_FPBuffer, g_FPBufferSize) > 0)
		{
			SendMessage(hwnd, MESSAGE_FP_RECEIVED, 0, 0);
		}
	}
    return 0;
}

void CSampleDlg::OnBnClickedBtnInit()
{
	int ret = 0;

	if(!gInited)
	{
		if(!loadZKFPCapLib())
		{
			MessageBox("Load ZKFPCap.dll failed");
			return;
		}

		if(!loadZKFingerLib())
		{
			MessageBox("Load ZKFinger10.dll failed");
			return;
		}

		ret = sensorInit();
		if(ret != 0)
		{
			char tmp[128] = {0};
			sprintf(tmp, "Init failed, ret=%d", ret);
			sensorFree();
			MessageBox(tmp);
			return;
		}

		CString str;
		CComboBox *ccb = (CComboBox*)GetDlgItem(IDC_COMBO_INDEX);
		ccb->ResetContent();
		ccb->EnableWindow(0);

		for(int i = 0; i < sensorGetCount(); i++)
		{
			str.Format(_T("%d"), i);
			ccb->AddString(str);
		}
		ccb->SetCurSel(0);
		ccb->EnableWindow();

		gInited = 1;
		GetDlgItem(IDC_BTN_OPEN)->EnableWindow(true);
		GetDlgItem(IDC_BTN_INIT)->SetWindowText("Free");
	}
	else
	{
		sensorFree();

		if(ZKFPCapLib)
		{
			FreeLibrary(ZKFPCapLib);
			ZKFPCapLib = NULL;
		}

		if(ZKFingerLib)
		{
			FreeLibrary(ZKFingerLib);
			ZKFingerLib = NULL;
		}

		CComboBox *ccb = (CComboBox*)GetDlgItem(IDC_COMBO_INDEX);
		ccb->ResetContent();
		ccb->EnableWindow(0);

		gInited = 0;
		GetDlgItem(IDC_BTN_OPEN)->EnableWindow(false);
		GetDlgItem(IDC_BTN_INIT)->SetWindowText("Init");
	}
}

void CSampleDlg::OnBnClickedBtnOpen()
{
	if(!gConnected)
	{
		g_FPBuffer = NULL;
		int ret = 0;
		char paramValue[64] = {0};

		int index = GetDlgItemInt(IDC_COMBO_INDEX);
		ZKFPCapHandle = sensorOpen(index);
		if(!ZKFPCapHandle)
		{
			MessageBox("Open sensor failed");
			return;
		}

		memset(paramValue, 0, 64);
		sensorGetVersion(paramValue, sizeof(paramValue));

		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 1, paramValue, &ret);
		g_nWidth = *((int *)paramValue);

		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 2, paramValue, &ret);
		g_nHeight = *((int *)paramValue);

		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 106, paramValue, &ret);
		g_FPBufferSize = *((int *)paramValue);

		// get vid&pid
		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 1015, paramValue, &ret);
		int nVid = *((WORD *)paramValue);
		int nPid = *((WORD *)(&paramValue[2]));
		
		// Manufacturer
		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 1101, paramValue, &ret);
		// Product
		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 1102, paramValue, &ret);
		// SerialNumber
		memset(paramValue, 0, 64);
		ret = sizeof(paramValue);
		sensorGetParameterEx(ZKFPCapHandle, 1103, paramValue, &ret);

		// Init ZKFinger
		WORD iSize[22] = {0};
		iSize[0] = g_nWidth;
		iSize[1] = g_nHeight;
		iSize[20] = g_nWidth;
		iSize[21] = g_nHeight;
		ZKFingerHandle = BIOKEY_INIT(0, iSize, NULL, NULL, 0);
		if(ZKFingerHandle == NULL)
		{
			MessageBox("BIOKEY_INIT failed");
			sensorClose(ZKFPCapHandle);
			ZKFPCapHandle = NULL;
			return;
		}

		// Set allow angle of Press Finger
		BIOKEY_SET_PARAMETER(ZKFingerHandle, 4, 180);

		// Set Matching threshold
		BIOKEY_MATCHINGPARAM(ZKFingerHandle, 0, THRESHOLD_MIDDLE);

		g_FPBuffer = (BYTE *)malloc(g_FPBufferSize);

		GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Please place your finger on the sensor");

		g_bIsTimeToDie = 0;
		if(NULL == gThread)
		{
			gThread = CreateThread(NULL, 0, GetImage, NULL, 0, NULL);
		}

		gConnected = 1;
		GetDlgItem(IDC_BTN_INIT)->EnableWindow(false);
		GetDlgItem(IDC_BTN_GREEN)->EnableWindow(true);
		GetDlgItem(IDC_BTN_RED)->EnableWindow(true);
		GetDlgItem(IDC_BTN_BEEP)->EnableWindow(true);
		GetDlgItem(IDC_BTN_ENROLL)->EnableWindow(true);
		GetDlgItem(IDC_BTN_IDENTIFY)->EnableWindow(true);
		GetDlgItem(IDC_BTN_OPEN)->SetWindowText("Close");
	}
	else
	{
		g_bIsTimeToDie = 1;
		WaitForSingleObject(gThread, 10000);
		CloseHandle(gThread);
		gThread = NULL;

		sensorClose(ZKFPCapHandle);
		ZKFPCapHandle = NULL;

		BIOKEY_DB_CLEAR(ZKFingerHandle);
		BIOKEY_CLOSE(ZKFingerHandle);
		ZKFingerHandle = NULL;

		gConnected = 0;
		GetDlgItem(IDC_BTN_INIT)->EnableWindow(true);
		GetDlgItem(IDC_BTN_GREEN)->EnableWindow(false);
		GetDlgItem(IDC_BTN_RED)->EnableWindow(false);
		GetDlgItem(IDC_BTN_BEEP)->EnableWindow(false);
		GetDlgItem(IDC_BTN_ENROLL)->EnableWindow(false);
		GetDlgItem(IDC_BTN_IDENTIFY)->EnableWindow(false);		
		GetDlgItem(IDC_BTN_OPEN)->SetWindowText("Open");
	}
}

LRESULT CSampleDlg::OnFPReceived(WPARAM wParam, LPARAM lParam)
{
	int ret = 0, fid = 0, score = 0, quality = 0, size = 0;
	BYTE tmp[2048] = {0};
	CString buf;

	HBITMAP hb = BuildImage(g_FPBuffer, g_nWidth, g_nHeight);
	GetDlgItem(IDC_STATIC_DRAWAREA)->SendMessage(STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hb);
	DeleteObject(hb);
	hb = NULL;

	if(gIsEnroll)
	{
		ret = BIOKEY_EXTRACT(ZKFingerHandle, g_FPBuffer, tmp, 0);
		if (ret > 0)
		{
			if(0 == gPressTimes)
			{
				memcpy(gTmp1, tmp, ret);
			}
			else if(1 == gPressTimes)
			{
				memcpy(gTmp2, tmp, ret);
			}
			else if(2 == gPressTimes)
			{
				memcpy(gTmp3, tmp, ret);
			}

			gPressTimes++;

			// Get fingerprint quality
			quality = BIOKEY_GETLASTQUALITY(ZKFingerHandle);
			buf.Format("%d", quality);
			GetDlgItem(IDC_EDT_QUALITY)->SetWindowText(buf.GetString());
				
			buf.Format(_T("Still press finger %d time"), REGISTER_FINGER_COUNT-gPressTimes);
			GetDlgItem(IDC_EDT_PROMPT)->SetWindowText(buf.GetString());

			if (gPressTimes == REGISTER_FINGER_COUNT)
			{
				memset(tmp, 0, 2048);
				size = BIOKEY_GENTEMPLATE_SP(ZKFingerHandle, gTmp1, gTmp2, gTmp3, 3, tmp);				
				if (size > 0)
				{
					BIOKEY_DB_ADD(ZKFingerHandle, ++gEnrollCount, size, tmp);
					buf.Format(_T("Enroll succeeded, fid=%d, totalCount=%d"), gEnrollCount, BIOKEY_DB_COUNT(ZKFingerHandle));
					GetDlgItem(IDC_EDT_PROMPT)->SetWindowText(buf.GetString());

					gIsEnroll = false;
				}
				else
				{					
					GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Enroll failed");
				}
				gPressTimes = 0;
			}
		}
		else
		{
			GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Extract template failed");
		}
	}
	else
	{
		if ((ret = BIOKEY_EXTRACT(ZKFingerHandle, g_FPBuffer, tmp, 0)) > 0)
		{
			// Get fingerprint quality
			quality = BIOKEY_GETLASTQUALITY(ZKFingerHandle);
			buf.Format("%d", quality);
			GetDlgItem(IDC_EDT_QUALITY)->SetWindowText(buf.GetString());

			ret = BIOKEY_IDENTIFYTEMP(ZKFingerHandle, tmp, &fid, &score);
			if(ret > 0)
			{
				buf.Format("Identification success, fid=%d, score=%d", fid, score);	
			}
			else
			{
				buf.Format("Identification failed, score = %d", score);
			}
			GetDlgItem(IDC_EDT_PROMPT)->SetWindowText(buf.GetString());
		}
		else
		{
			GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Extract template failed");
		}
	}

	return 0;
}

void CSampleDlg::OnClose()
{
	if(gConnected)
	{
		OnBnClickedBtnOpen();
	}

	if(gInited)
	{
		OnBnClickedBtnInit();
	}

	CDialog::OnClose();
}

void CSampleDlg::OnBnClickedBtnEnroll()
{
	gPressTimes = 0;
	GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Enroll fingerprint, please press finger 3 time");
	gIsEnroll = true;
}

void CSampleDlg::OnBnClickedBtnIdentify()
{
	GetDlgItem(IDC_EDT_PROMPT)->SetWindowText("Identify fingerprint, please place finger on the sensor");
	gIsEnroll = false;
}

void CSampleDlg::OnBnClickedBtnGreen()
{
	char paramValue[64] = {0};

	*((int *)paramValue) = 1;
	sensorSetParameterEx(ZKFPCapHandle, 102, paramValue, 4);

	Sleep(100);

	*((int *)paramValue) = 0;
	sensorSetParameterEx(ZKFPCapHandle, 102, paramValue, 4);
}

void CSampleDlg::OnBnClickedBtnRed()
{
	char paramValue[64] = {0};

	*((int *)paramValue) = 1;
	sensorSetParameterEx(ZKFPCapHandle, 103, paramValue, 4);

	Sleep(100);

	*((int *)paramValue) = 0;
	sensorSetParameterEx(ZKFPCapHandle, 103, paramValue, 4);
}

void CSampleDlg::OnBnClickedBtnBeep()
{
	char paramValue[64] = {0};

	*((int *)paramValue) = 1;
	sensorSetParameterEx(ZKFPCapHandle, 104, paramValue, 4);

	Sleep(100);

	*((int *)paramValue) = 0;
	sensorSetParameterEx(ZKFPCapHandle, 104, paramValue, 4);
}
